package pers.cz.controller;

import com.alibaba.fastjson.JSON;
import entity.DataBaseParamter;
import org.apache.commons.io.FileUtils;
import org.pentaho.di.core.KettleEnvironment;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.exception.KettleDatabaseException;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleXMLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import pers.cz.commons.holder.Holder;
import pers.cz.date.DateUtils;
import pers.cz.encrypt.Base64Utils;
import pers.cz.encrypt.DesUtil;
import pers.cz.excel.PoiOoxmlUtils;
import pers.cz.fastshardingquery.Application;
import pers.cz.fastshardingquery.enums.DbConfigItem;
import pers.cz.fastshardingquery.enums.OtherConfigItem;
import pers.cz.freemarker.Field;
import pers.cz.freemarker.FreeMarkerUtils;
import pers.cz.graph.common.enums.ConfigDbKeyEnum;
import pers.cz.graph.common.enums.ConfigKeyEnum;
import pers.cz.graph.common.enums.OtherConfigFileUseSetEnum;
import pers.cz.graph.common.enums.OutputDetailEnum;
import pers.cz.graph.conf.ConfigureWrapper;
import pers.cz.graph.runner.RunnerGenAllGraph4Callee;
import pers.cz.graph.runner.RunnerGenAllGraph4Caller;
import pers.cz.io.FoldPathEnum;
import pers.cz.io.IOUtils;
import pers.cz.jefconfig.config.JefConfiguration;
import pers.cz.kettle.DataSyncUtil;
import pers.cz.model.DatabaseDesign;
import pers.cz.model.DatabaseDesignConfMapping;
import pers.cz.model.DatabaseDesignConfig;
import pers.cz.model.DatabaseDesignDtlWithBLOBs;
import pers.cz.pub.RespBean;
import pers.cz.service.DatabaseDesignService;
import pers.cz.sql.SqlUtils;
import freemarker.template.Template;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.script.ScriptException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;

/**
 * 对应测试工具模块
 * @program: PostGirl-panent
 * @description: TestUtilController
 * @author: Cheng Zhi
 * @create: 2022-03-28 17:19
 **/
@RestController
@RequestMapping(path = "/api/testUtilController")
public class TestUtilController {

    @Autowired
    DatabaseDesignService databaseDesignService;


    @Value("${datasource.master.url}")
    String dbUrl;

    @Value("${datasource.master.username}")
    String dbUserName;

    @Value("${datasource.master.password}")
    String dbPassWord;

    /**
     *
     * @param map
     * @return 分表规则快查
     * @throws ScriptException
     * @throws IOException
     */
    @PostMapping("/fastShardingQuery")
    public RespBean fastShardingQuery(@RequestBody Map map) throws ScriptException, IOException, KettleException {

        String tableName = (String) map.get("tableName");
        String startDate = (String) map.get("startDate");
        String endDate = (String) map.get("endDate");
        String dataSource = (String) map.get("dataSource");
        KettleEnvironment.init();
        DataBaseParamter dbParamter  = JSON.parseObject(dataSource,DataBaseParamter.class);
        dbParamter.setPassword(DesUtil.decode(dbParamter.getPassword())); // 解密

        String[] dbXml = DataSyncUtil.initDataBase(dbParamter);
        DatabaseMeta databaseMeta = new DatabaseMeta(dbXml[0]);
        String url = databaseMeta.getURL();


        JefConfiguration.set(DbConfigItem.MASTER_DB_URL, url);
        JefConfiguration.set(DbConfigItem.MASTER_DB_USERNAME, dbParamter.getUserName());
        JefConfiguration.set(DbConfigItem.MASTER_DB_PASSWORD, dbParamter.getPassword());

        JefConfiguration.set(OtherConfigItem.SHARDING_TABLENAME, tableName.toUpperCase());
        JefConfiguration.set(OtherConfigItem.SHARDING_START_DATE, startDate);
        JefConfiguration.set(OtherConfigItem.SHARDING_END_DATE, endDate);
        String result = Application.singleQuery();

        return RespBean.ok("查询成功！", result);
    }

    /**
     * 静态调用链路分析
     * @param map
     * @return
     */
    @PostMapping("/genCallGraph")
    public void genCallGraph(@RequestBody Map map, HttpServletResponse response) throws IOException {

        String appName = (String) map.get("appName");
        String className = (String) map.get("className");
        String methodName = (String) map.get("methodName");
        String direction = (String) map.get("direction");
        String targetClassAndMethodName = className + ":" + methodName;
        ConfigureWrapper configureWrapper = new ConfigureWrapper();
        configureWrapper.setMainConfig(ConfigKeyEnum.CKE_APP_NAME, appName);
        configureWrapper.setMainConfig(ConfigKeyEnum.CKE_CALL_GRAPH_OUTPUT_DETAIL, OutputDetailEnum.ODE_2.getDetail());
        configureWrapper.setMainConfig(ConfigKeyEnum.CKE_THREAD_NUM, "20");
        configureWrapper.setMainConfig(ConfigKeyEnum.CKE_IGNORE_DUP_CALLEE_IN_ONE_CALLER, Boolean.FALSE.toString());
        configureWrapper.setMainConfig(ConfigKeyEnum.CKE_DB_INSERT_BATCH_SIZE, "1000");
        configureWrapper.setMainConfig(ConfigKeyEnum.CKE_CHECK_JAR_FILE_UPDATED, Boolean.TRUE.toString());
        configureWrapper.setMainConfig(ConfigKeyEnum.CKE_OUTPUT_ROOT_PATH, "");

        // 默认不使用H2
        configureWrapper.setMainConfig(ConfigDbKeyEnum.CDKE_DB_USE_H2, Boolean.FALSE.toString());
        configureWrapper.setMainConfig(ConfigDbKeyEnum.CDKE_DB_DRIVER_NAME, com.mysql.jdbc.Driver.class.getName());
        configureWrapper.setMainConfig(ConfigDbKeyEnum.CDKE_DB_URL,
                dbUrl);
        configureWrapper.setMainConfig(ConfigDbKeyEnum.CDKE_DB_USERNAME, dbUserName);
        configureWrapper.setMainConfig(ConfigDbKeyEnum.CDKE_DB_PASSWORD, dbPassWord);

        String currentOutputDirPath = "";
        if (direction.equals("callee")) {
            // 设置关键字
            configureWrapper.setOtherConfigSet(OtherConfigFileUseSetEnum.OCFUSE_METHOD_CLASS_4CALLEE, targetClassAndMethodName);
            RunnerGenAllGraph4Callee runnerGenAllGraph4Callee = new RunnerGenAllGraph4Callee();
            runnerGenAllGraph4Callee.run(configureWrapper);
            currentOutputDirPath = runnerGenAllGraph4Callee.getCurrentOutputDirPath();
        } else if (direction.equals("caller")) {
            // 设置关键字
            configureWrapper.setOtherConfigSet(OtherConfigFileUseSetEnum.OCFUSE_METHOD_CLASS_4CALLER, targetClassAndMethodName);
            RunnerGenAllGraph4Caller runnerGenAllGraph4Caller = new RunnerGenAllGraph4Caller();
            runnerGenAllGraph4Caller.run(configureWrapper);
            currentOutputDirPath = runnerGenAllGraph4Caller.getCurrentOutputDirPath();
        }
        String fullClassName = currentOutputDirPath + "/" + className + ".txt";

        File file = new File(fullClassName);
        IOUtils.downFileWithNetWork(response, file);
        FileUtils.deleteDirectory(new File(currentOutputDirPath));
    }

    @PostMapping("/deleteConf")
    public RespBean deleteConf(@RequestBody Map map) {
        String json = (String) map.get("json");
        DatabaseDesignConfig databaseDesignConfig = JSON.parseObject(json, DatabaseDesignConfig.class);
        this.databaseDesignService.deleteField(databaseDesignConfig);
        return RespBean.ok("删除成功");
    }
    @PostMapping("/updateConf")
    public RespBean updateConf(@RequestBody Map map) {

        String json = (String) map.get("json");
        DatabaseDesignConfig databaseDesignConfig = JSON.parseObject(json, DatabaseDesignConfig.class);
        this.databaseDesignService.updateField(databaseDesignConfig);
        return RespBean.ok("修改成功");
    }

    @PostMapping("/addConf")
    public RespBean addConf(@RequestBody Map map) {

        String typeName = (String) map.get("typeName");
        String type = (String) map.get("type");
        String aidbType = (String) map.get("aidbType");
        String mysqlType = (String) map.get("mysqlType");
        String oracleType = (String) map.get("oracleType");
        String antdbType = (String) map.get("antdbType");
        String postgresqlType = (String) map.get("postgresqlType");

        DatabaseDesignConfig databaseDesignConfig = new DatabaseDesignConfig();
        databaseDesignConfig.setType(type);
        databaseDesignConfig.setTypeName(typeName);
        List<DatabaseDesignConfMapping> list = new ArrayList<>();

        DatabaseDesignConfMapping databaseDesignConfMapping1 = new DatabaseDesignConfMapping();
        databaseDesignConfMapping1.setDatabaseType("aidb");
        databaseDesignConfMapping1.setFieldsType(aidbType);
        databaseDesignConfMapping1.setType(type);

        DatabaseDesignConfMapping databaseDesignConfMapping2 = new DatabaseDesignConfMapping();
        databaseDesignConfMapping2.setDatabaseType("mysql");
        databaseDesignConfMapping2.setFieldsType(mysqlType);
        databaseDesignConfMapping2.setType(type);

        DatabaseDesignConfMapping databaseDesignConfMapping3 = new DatabaseDesignConfMapping();
        databaseDesignConfMapping3.setDatabaseType("oracle");
        databaseDesignConfMapping3.setFieldsType(oracleType);
        databaseDesignConfMapping3.setType(type);

        DatabaseDesignConfMapping databaseDesignConfMapping4 = new DatabaseDesignConfMapping();
        databaseDesignConfMapping3.setDatabaseType("antdb");
        databaseDesignConfMapping3.setFieldsType(antdbType);
        databaseDesignConfMapping3.setType(type);

        DatabaseDesignConfMapping databaseDesignConfMapping5 = new DatabaseDesignConfMapping();
        databaseDesignConfMapping3.setDatabaseType("oracle");
        databaseDesignConfMapping3.setFieldsType(postgresqlType);
        databaseDesignConfMapping3.setType(type);

        list.add(databaseDesignConfMapping1);
        list.add(databaseDesignConfMapping2);
        list.add(databaseDesignConfMapping3);
        list.add(databaseDesignConfMapping4);
        list.add(databaseDesignConfMapping5);

        databaseDesignConfig.setFields(list);
        databaseDesignService.addField(databaseDesignConfig);
        return RespBean.ok("添加成功");
    }

    @PostMapping("/queryConf")
    public List<DatabaseDesignConfig> queryConfs() {
        return databaseDesignService.queryConfs();
    }
    /**
     * 查询数据模型明细信息
     * @param map
     * @return
     */
    @PostMapping("/queryDtl")
    public DatabaseDesignDtlWithBLOBs queryDtl(@RequestBody Map map) {
        Integer id = (Integer) map.get("id");
        return databaseDesignService.getDatabaseDesignDtlById(id);
    }

    @PostMapping("/addDtl")
    public RespBean addDtl(@RequestBody Map map, HttpServletRequest servletRequest) {

        String tableName = (String) map.get("tableName");
        String logic = (String) map.get("logic");
        String fieldInfo = (String) map.get("fieldInfo");
        String remark = (String) map.get("remark");
        String codeInfo = (String) map.get("codeInfo");
        String indexInfo = (String) map.get("indexInfo");

        int userId = Integer.valueOf(servletRequest.getAttribute("userId").toString());
        String nodeName = (String) map.get("name");
        Integer parentId = (Integer) map.get("id");
        String type = (String) map.get("type");

        DatabaseDesign databaseDesign = new DatabaseDesign();
        databaseDesign.setName(nodeName);
        databaseDesign.setParentId(parentId);
        databaseDesign.setType(type);
        databaseDesign.setUserId(userId);

        DatabaseDesignDtlWithBLOBs databaseDesignDtlWithBLOBs = new DatabaseDesignDtlWithBLOBs();
        databaseDesignDtlWithBLOBs.setCodeInfo(codeInfo);
        databaseDesignDtlWithBLOBs.setFieldInfo(fieldInfo);
        databaseDesignDtlWithBLOBs.setIndexInfo(indexInfo);
        databaseDesignDtlWithBLOBs.setTableName(tableName);
        databaseDesignDtlWithBLOBs.setRemark(remark);
        databaseDesignDtlWithBLOBs.setLogic(logic);

        this.databaseDesignService.addDtlAndNode(databaseDesignDtlWithBLOBs, databaseDesign);
        return RespBean.ok("添加成功");
    }

    @PostMapping("/updateDtl")
    public RespBean updateDtl(@RequestBody Map map) {
        Integer id = (Integer) map.get("id");
        String tableName = (String) map.get("tableName");
        String logic = (String) map.get("logic");
        String fieldInfo = (String) map.get("fieldInfo");
        String remark = (String) map.get("remark");
        String codeInfo = (String) map.get("codeInfo");
        String indexInfo = (String) map.get("indexInfo");

        DatabaseDesignDtlWithBLOBs databaseDesignDtlWithBLOBs = new DatabaseDesignDtlWithBLOBs();
        databaseDesignDtlWithBLOBs.setCodeInfo(codeInfo);
        databaseDesignDtlWithBLOBs.setFieldInfo(fieldInfo);
        databaseDesignDtlWithBLOBs.setIndexInfo(indexInfo);
        databaseDesignDtlWithBLOBs.setId(id);
        databaseDesignDtlWithBLOBs.setTableName(tableName);
        databaseDesignDtlWithBLOBs.setRemark(remark);
        databaseDesignDtlWithBLOBs.setLogic(logic);

        databaseDesignService.modifyDel(databaseDesignDtlWithBLOBs);
        return RespBean.ok("修改成功");
    }
    /**
     * 删除一个数据模型节点
     * @param map
     * @return
     */
    @PostMapping("/deleteNode")
    public RespBean deleteNode(@RequestBody Map map, HttpServletRequest servletRequest) {
        int userId = Integer.valueOf(servletRequest.getAttribute("userId").toString());
        Integer id = (Integer) map.get("id");
        String type = (String) map.get("type");

        if (type != null && type.equals("1")) {
            this.databaseDesignService.removeDtl(id);
        }

        DatabaseDesign databaseDesign = new DatabaseDesign();
        databaseDesign.setId(id);
        Integer integer = this.databaseDesignService.deleteNode(databaseDesign);
        return RespBean.ok("删除成功");
    }

    /**
     * 修改一个模型节点
     * @param map
     * @return
     */
    @PostMapping("/updateNode")
    public RespBean updateNode(@RequestBody  Map map, HttpServletRequest servletRequest) {
        int userId = Integer.valueOf(servletRequest.getAttribute("userId").toString());
        String nodeName = (String) map.get("name");
        Integer id = (Integer) map.get("id");

        DatabaseDesign databaseDesign = new DatabaseDesign();
        databaseDesign.setName(nodeName);
        databaseDesign.setId(id);
        Integer integer = this.databaseDesignService.updateNode(databaseDesign);
        return RespBean.ok("修改成功");
    }

    /**
     * 添加一个节点
     * @param map
     * @return
     */
    @PostMapping("/addNode")
    public RespBean addNode(@RequestBody  Map map, HttpServletRequest servletRequest) {
        int userId = Integer.valueOf(servletRequest.getAttribute("userId").toString());
        String nodeName = (String) map.get("name");
        Integer parentId = (Integer) map.get("id");
        String type = (String) map.get("type");

        DatabaseDesign databaseDesign = new DatabaseDesign();
        databaseDesign.setName(nodeName);
        databaseDesign.setParentId(parentId);
        databaseDesign.setType(type);
        databaseDesign.setUserId(userId);
        Integer integer = this.databaseDesignService.addNode(databaseDesign);
        return RespBean.ok("添加成功");
    }
    /**
     * 获取所有节点
     * @param servletRequest
     * @return
     */
    @PostMapping("/getDesignList")
    public List<DatabaseDesign> getDesignList(HttpServletRequest servletRequest) {
        int userId = Integer.valueOf(servletRequest.getAttribute("userId").toString());
        // 1、获取所有的数据，保存到List中
        List<DatabaseDesign> allDatabaseDesignByUserId = databaseDesignService.getAllDatabaseDesignByUserId(userId);

        return allDatabaseDesignByUserId;
    }


    /**
     * 自动生成回滚语句
     * @param map
     * @return
     */
    @PostMapping(path = "/getRollBackSql")
    public List<String> getRollBackSql(@RequestBody Map map) {

        List<String> sqls = (List<String>) map.get("sqls");

        String realSql = "";
        boolean needSplic = false; // 是否需要拼接;

        List<String> rollBackSqls = new ArrayList<>();
        for (String sql : sqls) {
            // 前端按行获取到的不一定是一个完整的sql，需要后台自动绝断。

            Holder holder = new Holder(sql);
            boolean[] booleans = judgeStringIncloud(holder, '1');
            //System.out.println("正常结束：" + booleans[0] + "-- 是注释行：" + booleans[1]);
            if (booleans[0] && !booleans[1] && !needSplic) {
                // 正常结束，非注释行 不需要拼接
                //System.out.println(SqlUtils.getRollbackSql((String) holder.getValue()));
                rollBackSqls.add(SqlUtils.getRollbackSql((String) holder.getValue()));
                realSql = "";
                needSplic = false;
            } else if (booleans[0] &&  booleans[1] && !needSplic) {
                // 正常结束，是注释行，不需要拼接
                //System.out.println(sql);
                rollBackSqls.add(sql);  // 为了保持生成的回退语句和insert语句位置对称，添加空行
                realSql = "";
                needSplic = false;
            } else if (!booleans[0] && !booleans[1]) {
                // 非正常结束，非注释行,需要拼接

                realSql = realSql +  sql + " ";
                needSplic = true;
                rollBackSqls.add("");  // 为了保持生成的回退语句和insert语句位置对称，添加空行
            } else if (!booleans[0] && booleans[1]) {
                // 非正常结束， 带有注释， 需要拼接。 这是需要去掉注释内容拼接
                // 把注释内容截取出来
                int index = sql.indexOf("--");
                sql = sql.substring(0, index);
                realSql = realSql +  sql + " ";
                needSplic = true;
                rollBackSqls.add("");  // 为了保持生成的回退语句和insert语句位置对称，添加空行
            } else if (booleans[0] && !booleans[1] && needSplic) {
                // 正常结束， 非注释行，需要拼接， 这时需要去执行真正的拼接好的sql.
                realSql = realSql +  sql + " ";
                // System.out.println(SqlUtils.getRollbackSql(realSql));
                rollBackSqls.add(SqlUtils.getRollbackSql(realSql));
                realSql = "";
                needSplic = false;
            } else if (booleans[0] && booleans[1] && needSplic) {
                // 正常结束， 含有注释行， 需要拼接。 生成回退语句默认不拼接注释
                realSql = realSql +  sql + " ";
                // 把注释内容截取出来
                int index = sql.indexOf("--");
                String commond = sql.substring(index);
                // System.out.println(SqlUtils.getRollbackSql(realSql) + " " + commond);
                rollBackSqls.add(SqlUtils.getRollbackSql(realSql) +  " " + commond);
                realSql = "";
                needSplic = false;
            }

        }
        return rollBackSqls;
    }

    public static boolean[] judgeStringIncloud (Holder strHolder, char ch) {
        boolean[] booleans = new boolean[2];
        booleans[0] = false; // 是否正常结束
        booleans[1] = false; // 是否注释行
        String str = (String) strHolder.getValue();
        // 目的是为了判断是否为注释行
        str = str.replaceAll("--", "^");
        char[] chars = str.toCharArray();

        if (chars.length <= 0) {
            str = "";
            strHolder.setValue(str);
            return booleans;
        }
        boolean isCommondLine = false;  // 判断是否为注释行
        boolean hasOneNotes = false;
        boolean isEnd = false;        // 判断是否分号结尾
        for (char c : chars) {

            // 如果第一个字符是空格，tab制表符则跳过
            if (c == ' ' || c == '\t') {
                continue;
            }

            if (c == '^') {
                isCommondLine = true;
            }

            if (c == ';' && !hasOneNotes) {
                isEnd = true;
            }

        }

        strHolder.setValue(str);
        booleans[0] = isEnd; // 是否正常结束
        booleans[1] = isCommondLine; // 是否注释行
        return booleans;

    }
    /**
     * 获取入参结构
     * @param map
     * @return
     */
    @PostMapping(path = "/getInputAndOutputMessage1")
    public Map<String, List<Field>> getInputAndOutputMessage1(@RequestBody Map map) {

        String input = (String) map.get("input");
        String outPut = (String) map.get("outPut");

        Map mapInput = FreeMarkerUtils.analyzeJson(input);
        Map mapOutput = FreeMarkerUtils.analyzeJson(outPut);
        mapOutput.putAll(mapInput);

        return mapInput;
    }

    @PostMapping(path = "/getInputAndOutputMessage")
    public List<Field> getInputAndOutputMessage(@RequestBody Map map) {

        String input = (String) map.get("input");
        String outPut = (String) map.get("outPut");

        Map mapInput = FreeMarkerUtils.analyzeJson(input);
        Map<String, List<Field>> mapOutput = FreeMarkerUtils.analyzeJson(outPut);
        mapOutput.putAll(mapInput);

        List<Field> list = new ArrayList<>();
        for (String key : mapOutput.keySet()) {
            list.addAll(mapOutput.get(key));
        }
        return list;
    }

    @PostMapping("/generateDoc")
    public void generateDoc(@RequestBody Map map, HttpServletResponse response) {
        try {
            String input = (String) map.get("input");                       // 入参报文
            String outPut = (String) map.get("outPut");                     // 参数
            String busiCode = (String) map.get("busiCode");                 // 接口编号
            String interfaceNameCh = (String) map.get("interfaceNameCh");   // 接口名称
            String interfaceNameEn = (String) map.get("interfaceNameEn");   // 接口名称英文
            List<Map> fields = (List<Map>) map.get("Field");                // 字段集
            String foreignMethod = (String) map.get("foreignMethod");       // 调用外部方法
            String interfaceDes = (String) map.get("interfaceDes");         // 接口描述

            // 将List转化为Map
            Map<String, Field> mapFields = new HashMap<>();
            for (Map map1 : fields){

                Field field = JSON.parseObject(JSON.toJSONString(map1), Field.class);
                mapFields.put(field.getParam(), field);
            }

            Map<String, Set<Field>> mapInput = FreeMarkerUtils.analyzeJson(input);
            Set<Field> inputList = new HashSet();
            interfaceNameEn = interfaceNameEn + "(";
            for (String key : mapInput.keySet()) {
                Field inputFile = new Field(key, "Object", "输入描述");
                interfaceNameEn = interfaceNameEn +  "Object " + key + ",";
                inputList.add(inputFile);
            }
            interfaceNameEn = interfaceNameEn.substring(0, interfaceNameEn.length()-1) + ");";
            Map<String, Set<Field>> mapOutput = FreeMarkerUtils.analyzeJson(outPut);
            Set<Field> outputList = new HashSet();
            for (String key : mapOutput.keySet()) {

                if (!key.equals("data")) {
                    continue;
                }
                Field outputFile = new Field(key, "Object", "输出描述");
                outputList.add(outputFile);
            }
            mapOutput.putAll(mapInput);

            // 用传入的List替换mapOutput中的list
            for (String key : mapOutput.keySet()) {

                Set<Field> list = (Set<Field>) mapOutput.get(key);
                Map<String,Field> mapNew = new HashMap<>();
                Iterator<Field> iterator = list.iterator();
                while (iterator.hasNext()) {
                    Field field = iterator.next();
                    Field field1 = mapFields.get(field.getParam()); // hashSet相同值不会覆盖
                    mapNew.put(field.getParam(), field1);
                }
                Set<Field> listNew = new HashSet<>();
                for (String keyNew : mapNew.keySet()) {
                    listNew.add(mapNew.get(keyNew));
                }

                mapOutput.put(key, listNew);
            }
            String templateName = "ImsApiTemplate.xml"; // 模板名称
            String path = IOUtils.getFoldPath(FoldPathEnum.TMPLATE_FILE);
            Template template = FreeMarkerUtils.loadTemplate(path, templateName);

            // 构建模板数据：
            Map<String, Object> templateMap = new HashMap<>();
            templateMap.put("interfaceNameCh", escape(interfaceNameCh));
            templateMap.put("busiCode", escape(busiCode));
            templateMap.put("interfaceDec", escape(interfaceDes));

            templateMap.put("interfaceNameEn", escape(interfaceNameEn));
            templateMap.put("externalMethod", escape(foreignMethod));
            templateMap.put("titleMap", mapOutput);
            // 输入和输出
            templateMap.put("firstInput", inputList);
            templateMap.put("FirstInput", inputList);
            templateMap.put("FirstOutput", outputList);
            File file = FreeMarkerUtils.writeFile(templateMap, template, busiCode + "接口API.doc");
            IOUtils.downFileWithNetWork(response, file);
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生产cosmic文档
     * @param file
     * @param response
     */
    @PostMapping("/generateCosmicDoc")
    public void generateCosmicDoc(@RequestParam("file") MultipartFile file, @RequestParam("firstTitle") String firstTitle, @RequestParam("secondTitle") String secondTitle, @RequestParam("content") String content, HttpServletResponse response) {
        String templateName = "CosmicTemplate.xml"; // 模板名称
        String path = IOUtils.getFoldPath(FoldPathEnum.TMPLATE_FILE);
        //String path  = this.getClass().getResource(templatePath).getPath();
        try {
            InputStream inputStream = file.getInputStream();
            String name = file.getOriginalFilename();
            String ext = name.substring(name.lastIndexOf(".") + 1).toLowerCase();
            PoiOoxmlUtils poiOoxmlUtils = new PoiOoxmlUtils();
            List list = new ArrayList();
            list.add(firstTitle);
            list.add(secondTitle);
            list.add(content);
            if (list.size() <= 0) {
                list.add("客户需求");
                list.add("功能过程");
                list.add("子过程描述");
            }
            Map map1 = poiOoxmlUtils.anaylizeExcel(inputStream, name, list);

            Template template = FreeMarkerUtils.loadTemplate(path, templateName);
            Map<String,Object> dataMap = new HashMap<>();
            dataMap.put("cosmicDatasMap", buildResultMap(map1));
            File wordFile = FreeMarkerUtils.writeFile(dataMap, template,ext +"-技术建议书.doc");

            IOUtils.downFileWithNetWork(response, wordFile);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @PostMapping("/generateDesignDoc")
    public void generateDesignDoc(@RequestBody Map map, HttpServletResponse response) throws Exception {

        String templateName = "DesignTemplate.xml"; // 模板名称
        String path = IOUtils.getFoldPath(FoldPathEnum.TMPLATE_FILE);

        String workOrderName = (String) map.getOrDefault("workOrderName", "工单名称");
        String author = (String) map.getOrDefault("author", "POSTGIRL");
        String requirementSummary = (String) map.getOrDefault("requirementSummary", "无");
        String requirementDecomposition = (String) map.getOrDefault("requirementDecomposition", "无");
        String conceptualDesign = (String) map.getOrDefault("conceptualDesign", "无");
        String systemFlowChart = (String) map.getOrDefault("systemFlowChart", "无");
        String extInterface = "无";
        String callInterface = "无";
        String secFuncListStr = (String) map.get("subFuncList");
        String input = (String) map.getOrDefault("input", "无");
        String outPut = (String) map.getOrDefault("output", "无");


        Map<String,Object> dataMap = new HashMap<>();
        Map<String, Map<String, String>> fundesMap = new HashMap<>();

        String imgFilePath = IOUtils.getFoldPath(FoldPathEnum.IMAGE_FILE);

        if (secFuncListStr != null && !secFuncListStr.isEmpty()) {
            List list = JSON.parseObject(secFuncListStr, List.class);

            list.forEach(str->{
                Map funcMap = JSON.parseObject((String) str.toString(), Map.class);
                String beforeAdjustment = (String) funcMap.get("beforeAdjustment");
                String afterAdjustment = (String) funcMap.get("afterAdjustment");
                String codeMethodDes = (String) funcMap.get("codeMethodDes");
                String businessScope = (String) funcMap.get("businessScope");
                String sceneDescription = (String) funcMap.get("sceneDescription");
                String impactDescription = (String) funcMap.get("impactDescription");
                String subFuncName = (String) funcMap.get("subFuncName");
                String imgName = (String) funcMap.get("imageName");

                Map<String, String> secFuncInfo = new HashMap();
                secFuncInfo.put("beforeAdjustment", escape(beforeAdjustment));
                secFuncInfo.put("afterAdjustment", escape(afterAdjustment));
                secFuncInfo.put("codeMethodDes", escape(codeMethodDes));
                secFuncInfo.put("businessScope", escape(businessScope));
                secFuncInfo.put("sceneDescription", escape(sceneDescription));
                secFuncInfo.put("impactDescription", escape(impactDescription));
                if ("6".equals(imgName)) {
                    String fileBase64 = (String) funcMap.get("fileBase64");
                    String symBol = "base64,";
                    fileBase64 = fileBase64.substring(fileBase64.indexOf(symBol) + symBol.length(), fileBase64.length());
                    secFuncInfo.put("view", fileBase64);
                } else {
                    File file = new File(imgFilePath+"/"+imgName+".png");
                    secFuncInfo.put("view", Base64Utils.img2Base(file));
                }

                fundesMap.put(subFuncName, secFuncInfo);
            });
            //dataMap.put("funcDesMap", fundesMap);
        }
        dataMap.put("funcDesMap", fundesMap);

        dataMap.put("workOrderName", escape(workOrderName));
        dataMap.put("currentDate", DateUtils.format(new Date(), "YYYY年MM月dd日"));
        dataMap.put("author", escape(author));
        dataMap.put("requirementSummary", escape(requirementSummary));
        dataMap.put("requirementDecomposition", escape(requirementDecomposition));
        dataMap.put("conceptualDesign", escape(conceptualDesign));
        dataMap.put("systemFlowChart", escape(systemFlowChart));
        dataMap.put("extInterface", escape(extInterface));
        dataMap.put("callInterface", escape(callInterface));


        Set<Field> inputList = new HashSet();
        Set<Field> outputList = new HashSet();
        Map<String, Set<Field>> mapOutput = new HashMap<>();
        if (!input.isEmpty() && !"无".equals(input)) {
            Map<String, Set<Field>> mapInput = FreeMarkerUtils.analyzeJson(input);
            for (String key : mapInput.keySet()) {
                Field inputFile = new Field(key, "Object", "输入描述");
                inputList.add(inputFile);
            }
            mapOutput.putAll(mapInput);
        }

        if (!outPut.isEmpty() && !"无".equals(outPut)) {
            Map<String, Set<Field>> mapOutput1 = FreeMarkerUtils.analyzeJson(outPut);

            for (String key : mapOutput1.keySet()) {

                if (!key.equals("data")) {
                    continue;
                }
                Field outputFile = new Field(key, "Object", "输出描述");
                outputList.add(outputFile);
            }
            mapOutput.putAll(mapOutput1);
        }

        dataMap.put("FirstOutput", outputList);
        dataMap.put("FirstInput", inputList);
        dataMap.put("titleMap", mapOutput);


        Template template = FreeMarkerUtils.loadTemplate(path, templateName);
        File wordFile = FreeMarkerUtils.writeFile(dataMap, template,"开发设计文档.doc");

        IOUtils.downFileWithNetWork(response, wordFile);

    }
    /**
     * 构建第二个map
     * @param firstMap
     */
    private Map<String, Object> buildResultMap(Map<String, Object> firstMap) {

        Map<String, Object> myMap = new LinkedHashMap<>();
        for (String key : firstMap.keySet()) {

            if ( key == null || key.equals("")) {
                continue;
            }
            List<Map<String, String>> maps = (List<Map<String, String>>) firstMap.get(key);
            // {真实姓名=这是我的真实名字}, {虚拟名字=这是我的虚拟名字}, {虚拟名字=这是别人的虚拟名字}, {微信名字=这是我的微信名字}
            Iterator<Map<String, String>> iterator = maps.iterator();
            Map<String, String> resultMap = new LinkedHashMap<>();
            while (iterator.hasNext()) {
                Map<String, String> map = iterator.next();
                for (String mapKey : map.keySet()) {
                    String s = resultMap.get(mapKey);
                    if (s != null ) {
                        if (s.equals("")) {
                            continue;
                        }
                        s = s + "，" + map.get(mapKey);
                        resultMap.put(mapKey,s);
                    } else {
                        if (mapKey == null || mapKey.equals("")) {
                            continue;
                        }
                        resultMap.put(mapKey, map.get(mapKey));
                    }
                }
            }

            myMap.put(key, resultMap);
        }
        return myMap;
    }

    /**
     * 特殊字符转义
     * @param interfaceDes
     * @return
     */
    private String escape(String interfaceDes) {

        return interfaceDes.replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll("&","&amp;").replaceAll("\r|\n", "<w:br/>");
    }
}
